package zhh.tangbao.machine.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import zhh.tangbao.commodity.constant.MachineRunningState;
import zhh.tangbao.commodity.constant.OrderStatus;
import zhh.tangbao.commodity.constant.PickupStatus;
import zhh.tangbao.commodity.dao.CommodityMachineEntityDao;
import zhh.tangbao.commodity.dao.CommodityMachineStockDao;
import zhh.tangbao.commodity.dao.CommodityOrderContentDao;
import zhh.tangbao.commodity.dao.CommodityOrderDao;
import zhh.tangbao.commodity.dto.CommodityMachineStockUpdateDto;
import zhh.tangbao.commodity.entity.CommodityMachineEntity;
import zhh.tangbao.commodity.entity.CommodityOrder;
import zhh.tangbao.commodity.manager.OrderPickUpManager;
import zhh.tangbao.commodity.manager.pickup.PickUpOrder;
import zhh.tangbao.commodity.manager.pickup.PickUpOrderContent;
import zhh.tangbao.machine.dto.PickUpDto;
import zhh.tangbao.machine.dto.TicketCheckDto;
import zhh.tangbao.machine.manager.ConnectionManager;
import zhh.tangbao.machine.util.MachineHolderUtil;
import zhh.tangbao.machine.vo.StockInfo;
import zhh.tangbao.system.constant.DataStatus;
import zhh.tangbao.system.exception.ServiceException;
import zhh.tangbao.system.utils.EncryptUtil;
import zhh.tangbao.system.utils.ZhhStringUtil;
import zhh.tangbao.websocket.WebSocketSendMessageService;
import zhh.tangbao.websocket.WebSocketServiceType;
import zhh.tangbao.websocket.pojo.MachineRunning;
import zhh.tangbao.websocket.pojo.WebSocketMessageEntity;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 *     描述
 * </p>
 * @author 粥灰灰
 * <p>2023/3/27</p>
 */

@Service
public class MachineConnectService {

    @Autowired
    private CommodityOrderContentDao contentDao;

    @Autowired
    private CommodityMachineEntityDao dao;

    @Autowired
    private ConnectionManager connectionManager;

    @Autowired
    private OrderPickUpManager pickUpManager;

    @Autowired
    private CommodityMachineStockDao stockDao;

    @Autowired
    private EncryptUtil encryptUtil;

    @Autowired
    private CommodityOrderDao orderDao;

    @Autowired
    private WebSocketSendMessageService sendMessageService;

    @Autowired
    private MachineHolderUtil util;
    public String open(String code) {
        // 校验激活码是否存在
        CommodityMachineEntity machine = dao.selectOne(new QueryWrapper<CommodityMachineEntity>().eq("activation_code", code).eq("data_status", DataStatus.ENABLE));
        Assert.notNull(machine, "激活码不正确");
        String vcode = ZhhStringUtil.randomString32();
        connectionManager.setPreConnectionVerificationCode(vcode, machine.getId(), machine.getActivationCode());
        return vcode;
    }

    public PickUpOrder checkTicket(TicketCheckDto dto) {
        String pickTicket = dto.getTicket();
        String acode = dto.getCode();
        Assert.notBlank(pickTicket, "请输入取货凭证");
        Assert.notBlank(acode, "机器对不上");
        String machineId = util.getMachineId(acode);
        PickUpOrder head = pickUpManager.getHead(machineId);
        Assert.notNull(head, "当前售货机中没有待取订单");
        String s = encryptUtil.MD5(head.getOrderId());
        Assert.equals(pickTicket, s, "还未到当前订单取货");
        return head;
    }

    @Transactional
    public void pickUp(PickUpDto dto) {
        String acode = dto.getAcode();
        String orderId = dto.getOrderId();
        String machineId = util.getMachineId(acode);
        Assert.notNull(machineId, "该机器不存在或者未上线");
        Assert.notNull(orderId, "订单号不能为空");
        PickUpOrder pick = pickUpManager.getHead(machineId);
        if (!orderId.equals(pick.getOrderId())) {
            throw new ServiceException("当前待取货订单与队列订单不符");
        }
        List<PickUpOrderContent> contents = pick.getContents();
        Assert.notEmpty(contents, "当前订单没有待取货物品或已被取完");
        contentDao.updateContentsPickupStatus(orderId, machineId, PickupStatus.PICKED);
        // 减少售货机库存
        // 该部分是用户已购买后待取货的数量，而因为这些货品已经处于待取货状态，没有其他人可以中途抢断，所以无需检测库存是否足够，因为待取货物数量必定足够
        List<CommodityMachineStockUpdateDto> cmsud = Lists.newArrayList();
        List<Integer> ids = contents.stream().map(PickUpOrderContent::getStockId).collect(Collectors.toList());
        List<StockInfo> s = stockDao.listStockInfoByIds(ids);
        Map<Integer, StockInfo> stockInfoMap = CollUtil.isNotEmpty(s) ? s.stream().collect(Collectors.toMap(StockInfo::getStockId, Function.identity())) : Maps.newHashMap();
        List<String> commodityId = Lists.newArrayList();
        int size = contents.size();
        for (int i = 0; i < size; i++) {
            PickUpOrderContent poc = contents.get(i);
            CommodityMachineStockUpdateDto commodityMachineStockUpdateDto = new CommodityMachineStockUpdateDto(poc.getStockId(), -poc.getCommodityEntityCount());
            cmsud.add(commodityMachineStockUpdateDto);
            StockInfo stockInfo = stockInfoMap.get(poc.getStockId());
            if (null != stockInfo && stockInfo.getTotalRemain() - poc.getCommodityEntityCount() <= stockInfo.getWarnThresholdValue()) {
                commodityId.add(poc.getCommodityEntityId());
            }
        }
        stockDao.reduceStockTotalRemainCount(cmsud, ids);
        pickUpManager.pickUp(machineId);
        if (pickUpManager.checkOrderCompleted(orderId)) {
            CommodityOrder update = new CommodityOrder();
            update.setUpdateInfo("系统");
            update.setOrderStatus(OrderStatus.PICKED.getCode());
            orderDao.update(update, new QueryWrapper<CommodityOrder>().eq("id", orderId));
        }
        if (CollUtil.isNotEmpty(commodityId)) {
            new Thread(() -> {
                WebSocketMessageEntity entity = new WebSocketMessageEntity(WebSocketServiceType.MESSAGE);
                entity.setTitle("商品缺货");
                entity.setContent(String.format("编号%s售货机商品缺货\n商品编号:%s", machineId, commodityId.toString()));
                sendMessageService.sendMessageToAll("系统", entity);
                sendMessageService.sendMessageToAll(null, new WebSocketMessageEntity(WebSocketServiceType.MACHINE, new MachineRunning(machineId, MachineRunningState.RUNNING, pickUpManager.getQueueSize(machineId))));

            }).start();
        }
    }
}
